/* 
 * File:   mcrypt
 * Author: along
 * 
 * Created on 2011年11月27日, 下午3:10
 */

#include "Mcrypt.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mcrypt.h>

char gKey[2048];
char gIV[2048];
MCRYPT gTd;
MCRYPT gTd2;

struct Ret {
    char * data;
    int size;
} crypt_buf2, crypt_buf1, decrypt_buf1;

void makesure_bufsize(struct Ret * r, int len) {
    if (len > r->size) {
        free(r->data);
        r->data = (char*) malloc(len);
        r->size = len;
    }
}

int wtt_mcrypt_module_open(char *algorithm, char *mode, char *key) {

    memset(gKey, '\0', 1024);
    memset(gIV, '\0', 1024);
    crypt_buf1.data = NULL;
    crypt_buf1.size = 0;
    crypt_buf2.data = NULL;
    crypt_buf2.size = 0;
    decrypt_buf1.data = NULL;
    decrypt_buf1.size = 0;
    makesure_bufsize(&crypt_buf1, 1024);
    makesure_bufsize(&crypt_buf2, 512);
    makesure_bufsize(&decrypt_buf1, 512);

    gTd = mcrypt_module_open(algorithm, NULL, mode, NULL);
    if (gTd == MCRYPT_FAILED) {
        fprintf(stderr, "failed to open algorithm!\n");
        return 0;
    }

    int keysize = mcrypt_enc_get_key_size(gTd);
    strncpy(gKey, key, keysize);
    int ivsize = mcrypt_enc_get_iv_size(gTd);
    if (ivsize > 0) {
        for (int t = 0; t < ivsize; t++)
            gIV[t] = (t * 2 % 255) + 15;
    }
    if (mcrypt_generic_init(gTd, gKey, keysize, gIV) < 0) {
        fprintf(stderr, "Failed to Initialize algorithm!\n");
        return 0;
    }

    gTd2 = mcrypt_module_open(algorithm, NULL, mode, NULL);
    if (gTd2 == MCRYPT_FAILED) {
        fprintf(stderr, "failed to open algorithm!\n");
        return 0;
    }
    if (mcrypt_generic_init(gTd2, gKey, keysize, gIV) < 0) {
        fprintf(stderr, "Failed to Initialize algorithm!\n");
        return 0;
    }
    
    //printf("key:%s\n", gKey);
    return 1;
}

char* wtt_mcrypt_generic(char *plaintext) {

    int siz = (mcrypt_enc_is_block_mode(gTd) != 0)
            ? (strlen(plaintext) / mcrypt_enc_get_block_size(gTd)) * mcrypt_enc_get_block_size(gTd)
            : strlen(plaintext);

    makesure_bufsize(&crypt_buf1, siz + 1);
    strncpy(crypt_buf1.data, plaintext, siz)[siz] = '\0';
    mcrypt_generic(gTd, crypt_buf1.data, siz);

    makesure_bufsize(&crypt_buf2, siz * 2 + 1);
    for (int i = 0; i < siz; i++) {
        unsigned char c = crypt_buf1.data[i];
        sprintf(crypt_buf2.data + i * 2, "%02x", c);
    }
    crypt_buf2.data[siz * 2] = '\0';

    return crypt_buf2.data;
}

char* wtt_mdecrypt_generic(char *plaintext) {

    int len = strlen((char*) plaintext);
    makesure_bufsize(&decrypt_buf1, len / 2 + 1);

    char buf[3] = {0};
    for (int i = 0; i < len; i += 2) {
        strncpy(buf, plaintext + i, 2);
        int c;
        sscanf(buf, "%x", &c);
        decrypt_buf1.data[i / 2] = c;
    }

    mdecrypt_generic(gTd2, decrypt_buf1.data, len / 2);
    decrypt_buf1.data[len / 2] = '\0';

    return decrypt_buf1.data;
}

void wtt_mcrypt_module_close() {

    free(crypt_buf1.data);
    free(crypt_buf2.data);
    mcrypt_generic_deinit(gTd);
    mcrypt_module_close(gTd);
}

